package com.echo.im.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.echo.im.common.model.message.IMPrivateMessage;
import com.echo.im.common.model.IMUserInfo;
import com.echo.im.platform.core.context.SessionContext;
import com.echo.im.platform.core.context.UserSession;
import com.echo.im.platform.core.dto.PrivateMessageDTO;
import com.echo.im.platform.core.dto.PullOfflineMessageDto;
import com.echo.im.platform.core.dto.RecallMessageDTO;
import com.echo.im.platform.core.enums.MessageStatus;
import com.echo.im.platform.core.enums.MessageType;
import com.echo.im.platform.core.utils.Idgenerator;
import com.echo.im.common.vo.message.PrivateMessageVO;

import com.echo.im.platform.manager.FriendManager;
import com.echo.im.platform.manager.PrivateMessageManager;
import com.echo.im.platform.service.PrivateMessageService;
import com.echo.im.repository.dao.entity.OfflineMessage;
import com.echo.im.repository.dao.entity.PrivateMessage;
import com.echo.im.repository.dao.mapper.PrivateMessageMapper;
import com.echo.im.repository.offline.OfflineMessageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import cn.hutool.core.bean.BeanUtil;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 私聊消息服务实现
 * @author echo
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper, PrivateMessage> implements PrivateMessageService {

    private final FriendManager friendManager;
    private final PrivateMessageManager privateMessageManager;
    private final OfflineMessageService<PrivateMessage> privateMessageOfflineMessageService;

    @Override
    public PrivateMessageVO sendMessage(PrivateMessageDTO dto) {
        //校验
        UserSession session = SessionContext.getSession();

        //判断是不是好友
        friendManager.checkFriend(session.getUserId(), dto.getRecvId());

        // 过滤内容中的敏感词

        // 推送消息
        PrivateMessageVO privateMessageVO = BeanUtil.copyProperties(dto, PrivateMessageVO.class);
        IMPrivateMessage imPrivateMessage = new IMPrivateMessage();
        imPrivateMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
        imPrivateMessage.setFirstRecvId(privateMessageVO.getRecvId());
        imPrivateMessage.setSendToSelf(true);
        imPrivateMessage.setData(privateMessageVO);
        imPrivateMessage.setSendResult(true);


        privateMessageManager.sendAndSave(imPrivateMessage);

        return privateMessageVO;
    }

    /**
     *
     * 1.消息是否存在直接丢到客户端判断，我们这里不用判断
     * 2.是否有权撤回消息，例如撤回消息的发送者和被撤回消息的发送者是否相同
     * 3.消息超过时间也由双方客户端判断，如果消息超过xxx分钟，不支持撤回
     * 4.如何知道撤回是否成功呢？如果撤回成功，对端将会回一条撤回成功消息
     * 5.privateStoreMessageListener 要判断撤回消息是否超时，如果超时，就不管他了
     *
     * @param dto
     */
    @Override
    public void recallMessage(RecallMessageDTO dto) {
        //校验
        UserSession session = SessionContext.getSession();

        friendManager.checkFriend(session.getUserId(), dto.getRecvId());

        //伪造一条撤回消息，指定撤回消息的 ID,消息类型为 撤回类型，消息内容存放要撤回消息的msgId
        PrivateMessage privateMessage = PrivateMessage.builder()
                .id(Idgenerator.getMsgId())
                .sendId(session.getUserId())
                .recvId(dto.getRecvId())
                .type(MessageType.RECALL.code())
                .content(dto.getRecallMsgId())
                .sendTime(new Date())
                .status(MessageStatus.UNSEND.code()).build();


        // 推送消息
        PrivateMessageVO privateMessageVO = BeanUtil.copyProperties(privateMessage, PrivateMessageVO.class);
        IMPrivateMessage imPrivateMessage = new IMPrivateMessage();
        imPrivateMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
        imPrivateMessage.setFirstRecvId(privateMessageVO.getRecvId());
        imPrivateMessage.setSendToSelf(false);
        imPrivateMessage.setData(privateMessageVO);
        imPrivateMessage.setSendResult(false);

        privateMessageManager.sendAndSave(imPrivateMessage);

        // 推给自己其他终端
        privateMessageVO.setContent("你撤回了一条消息");
        imPrivateMessage.setSendToSelf(true);
        imPrivateMessage.setRecvTerminals(Collections.emptyList());

        privateMessageManager.sendAndSave(imPrivateMessage,false);

        log.info("撤回私聊消息，发送id:{},接收id:{}，内容:{}", privateMessage.getSendId(), privateMessage.getRecvId(), privateMessage.getContent());
    }

    /**
     * 拉取离线消息,uuid可以是前端生成，也可以是后端通过ip等这些来设置，后期可以更改
     */
    @Override
    public List<PrivateMessageVO> pullOfflineMessage(PullOfflineMessageDto dto) {

        UserSession session = SessionContext.getSession();
        List<PrivateMessage> offLineMessages =
                privateMessageOfflineMessageService.fetchAndDeleteOfflineMessages(session.getUserId(), dto.getLastMsgId(), dto.getSize(), dto.getSessionUuid());
        List<PrivateMessageVO> privateMessageVOList = BeanUtil.copyToList(offLineMessages, PrivateMessageVO.class);
        return privateMessageVOList;
    }

    /**
     * 伪装成一条消息，跟撤回类似，该消息的语义是将xxx消息设为已读，只发送给对端，不用同步给自己
     * @param friendId
     */
    @Override
    public void readedMessage(Long friendId) {
        //校验
        UserSession session = SessionContext.getSession();

        friendManager.checkFriend(session.getUserId(), friendId);

        //伪造一条撤回消息，指定撤回消息的 ID,消息类型为 撤回类型，消息内容存放要撤回消息的msgId


        // 推送消息
        PrivateMessageVO privateMessageVO = new PrivateMessageVO();
        privateMessageVO.setId(Idgenerator.getMsgId());
        privateMessageVO.setSendId(session.getUserId());
        privateMessageVO.setRecvId(friendId);
        privateMessageVO.setType(MessageType.READED.code());
        privateMessageVO.setContent(null);
        privateMessageVO.setSendTime(new Date());
        privateMessageVO.setStatus(MessageStatus.UNSEND.code());

        IMPrivateMessage sendMessage = new IMPrivateMessage();
        sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
        sendMessage.setFirstRecvId(privateMessageVO.getRecvId());
        sendMessage.setSendToSelf(false);
        sendMessage.setData(privateMessageVO);
        sendMessage.setSendResult(false);

        privateMessageManager.sendAndSave(sendMessage);

        log.info("撤回私聊消息，发送id:{},接收id:{}，内容:{}", privateMessageVO.getSendId(), privateMessageVO.getRecvId(), privateMessageVO.getContent());

    }


    /**
     * 直接查询数据库，不支持分页，不能用分页，只能用，上一次查询的Id，然后做limit ？，增量查询
     * @param friendId
     * @param lastMsgId
     * @param size
     * @return
     */
    @Override
    public List<PrivateMessageVO> findHistoryMessage(Long friendId, Long lastMsgId,Integer size) {

        Long userId = SessionContext.getSession().getUserId();

        QueryWrapper<PrivateMessage> wrapper = new QueryWrapper<>();
        wrapper.lambda().and(wrap -> wrap.and(
                                wp -> wp.eq(PrivateMessage::getSendId, userId)
                                        .eq(PrivateMessage::getRecvId, friendId))
                        .or(wp -> wp.eq(PrivateMessage::getRecvId, userId)
                                .eq(PrivateMessage::getSendId, friendId)))
                .ne(PrivateMessage::getStatus, MessageStatus.RECALL.code())
                .gt(PrivateMessage::getId, lastMsgId)
                .orderByDesc(PrivateMessage::getId)
                .last("limit " + size);

        List<PrivateMessage> messages = baseMapper.selectList(wrapper);

        List<PrivateMessageVO> messageInfos = messages.stream().map(m -> BeanUtil.copyProperties(m, PrivateMessageVO.class)).collect(Collectors.toList());
        log.info("拉取聊天记录，用户id:{},好友id:{}，数量:{}", userId, friendId, messageInfos.size());

        return messageInfos;
    }


}
